#include "jsnix.h"
#include <signal.h>
#include <semaphore.h>
#include <mqueue.h>

static int _os_sleep(JSCTX * ctx){
        unsigned int secs = __get_number_value(ctx, 0);

        unsigned int rc = sleep(secs);
	__put_int_value(ctx, rc);

       return 1;
}

static int _os_usleep(JSCTX *ctx){
        unsigned int usecs = __get_number_value(ctx, 0);
        __put_int_value(ctx, usleep(usecs));

	return 1;
}

static int _os_time(JSCTX *ctx)
{
	__put_int_value(ctx, time(NULL));

        return 1;
}



static void set_object_tm(JSCTX*ctx, struct tm *tm)
{
	int oid = __start_object(ctx);
	__put_int_prop(ctx, oid, "sec", tm->tm_sec);
	__put_int_prop(ctx, oid, "min", tm->tm_min);
	__put_int_prop(ctx, oid, "hour", tm->tm_hour);
	__put_int_prop(ctx, oid, "mday", tm->tm_mday);
	__put_int_prop(ctx, oid, "mon", tm->tm_mon+1);
	__put_int_prop(ctx, oid, "year", tm->tm_year + 1900);
	__put_int_prop(ctx, oid, "wday", tm->tm_wday);
	__put_int_prop(ctx, oid, "isdst", tm->tm_isdst);
}

static int _os_localtime(JSCTX *ctx)
{
	time_t t;
	if(__count(ctx) > 0)
		t = __get_int_value(ctx, 0);
	else
		t = time(NULL);

	struct tm *tm = localtime(&t);
	if(tm)
		set_object_tm(ctx, tm);
	else
		__start_object(ctx);

	return 1;		
}

static int _os_gettimeofday(JSCTX *ctx)
{
	struct timeval tv;

	gettimeofday(&tv, NULL);
	int oid = __start_object(ctx);
	__put_int_prop(ctx, oid, "sec", tv.tv_sec);
	__put_int_prop(ctx, oid, "usec", tv.tv_usec);

	return 1;
}

static int _os_strftime(JSCTX *ctx){
	time_t t = __get_int_value(ctx, 0);
	struct tm *tm = localtime(&t);
	char outstr[64];

	if (strftime(outstr, sizeof(outstr), "%a, %d %b %Y %T %z", tm) == 0) {
		return 0;
	}

	__put_string_value(ctx, outstr);
	return 1;
}

static int _os_strptime(JSCTX *ctx){
	char *str = __get_string_value(ctx, 0);
	struct tm tm;

	strptime(str, "%a, %d %b %Y %T %z", &tm);
	__put_int_value(ctx, mktime(&tm));

	return 1;
}
static int _os_error(JSCTX *ctx)
{
	int oid = __start_object(ctx);
	
	__put_int_prop(ctx, oid, "errno", errno);
	if(errno)
		__put_string_prop(ctx, oid, "errmsg", strerror(errno));

	return 1;
}
static int _os_sysinfo(JSCTX *ctx)
{
        struct sysinfo si;

        sysinfo(&si);
        int oid = __start_object(ctx);
	__put_int_prop(ctx, oid, "uptime", si.uptime);
	__put_number_prop(ctx, oid, "load_1m", si.loads[0]);
	__put_number_prop(ctx, oid, "load_5m", si.loads[1]);
	__put_number_prop(ctx, oid, "load_15m", si.loads[2]);
	__put_number_prop(ctx, oid, "freeram", si.freeram);
	__put_number_prop(ctx, oid, "sharedram", si.sharedram);
	__put_number_prop(ctx, oid, "bufferram", si.bufferram);
	__put_number_prop(ctx, oid, "totalswap", si.totalswap);
	__put_number_prop(ctx, oid, "freeswap", si.freeswap);
	__put_number_prop(ctx, oid, "procs", si.procs);

        return 1;
}
static int _os_alarm(JSCTX *ctx)
{
	__put_number_value(ctx, alarm(__get_int_value(ctx, 0)));
	return 1;
}
static int _os_kill(JSCTX *ctx)
{
	__put_number_value(ctx, kill(__get_int_value(ctx, 0), __get_int_value(ctx, 1)));
	return 1;
}

static JSCTX *s_os_ctx = NULL;
static char *s_signal_handler = NULL;
static void _os_on_signal(int signum){
	printf("_os_on_signal: signum=%d\n", signum);

	if(s_os_ctx != NULL){
		if(s_signal_handler != NULL)
		{
			char call[80];
			int ret;

			sprintf(call, "%s(%d);", s_signal_handler, signum);
			duk_eval_string(s_os_ctx, call);
			ret = __get_int_value(s_os_ctx, -1);			
			duk_pop(s_os_ctx);

			printf("signal_handler return %d\n", ret);
		}
	}	
}

static int _os_set_signal_handler(JSCTX *ctx)
{
	char * handler = __get_string_value(ctx, -1);
	int rc = 0;
	if(handler)
	{
		if(s_signal_handler)
			free(s_signal_handler);
		s_signal_handler = strdup(handler);
		rc = 1;
	}
	else
	{
		if(s_signal_handler)
			free(s_signal_handler);
		s_signal_handler = NULL;
	}

	__put_int_value(ctx, rc);
	return 1;
}

static int _os_signal(JSCTX *ctx)
{
	int signum = __get_int_value(ctx, 0);
	char *sigtype = "";
	int handler = (int)_os_on_signal;

	if(__count(ctx) > 1)
		sigtype = __get_string_value(ctx, 1);
	printf("signal::signum=%d\n", signum);

	if(strcmp(sigtype, "SIG_IGN") == 0)
		handler = SIG_IGN;
	else if(strcmp(sigtype, "SIG_DFL") == 0)
		handler = SIG_DFL;
	else
		printf("set signalhandler for %d\n", signum);
	printf("signal::signum=%d, handler=0x%x\n", signum, handler);

	signal(signum, handler);

	return 0;
}


static int _os_eval_file(JSCTX *ctx)
{
	const char *filename = __get_string_value(ctx, 0);
	int rc;

   	duk_eval_file(ctx, filename);
	rc = duk_get_int(ctx, -1);
	duk_pop(ctx);

	__put_int_value(ctx, rc);
	return 1;
}

static int _os_eval_string(JSCTX *ctx)
{
	const char *str = __get_string_value(ctx, 0);
	duk_eval_string(ctx, str);
	int ret = __get_int_value(ctx, -1);
	duk_pop(ctx);

	__put_int_value(ctx, ret);
	return 1;
}

static int _os_getenv(JSCTX *ctx)
{
	const char *name = __get_string_value(ctx, 0);
	__put_string_value(ctx, getenv(name));
	return 1;
}

static int _os_setenv(JSCTX *ctx)
{
	const char *name = __get_string_value(ctx, 0);
	const char *value = __get_string_value(ctx, 1);

	__put_int_value(ctx, setenv(name, value, 1));

	return 1;
}


int load_os_module(JSCTX *ctx){

	s_os_ctx = ctx;

	__start_global_object(ctx, "os");
	__register_function(ctx, "sleep", _os_sleep, 1);
	__register_function(ctx, "usleep", _os_usleep, 1);
	__register_function(ctx, "time", _os_time, 0);
	__register_function(ctx, "localtime", _os_localtime, __VARARGS);
	__register_function(ctx, "strftime", _os_strftime, 1);
	__register_function(ctx, "strptime", _os_strptime, 1);
	__register_function(ctx, "gettimeofday", _os_gettimeofday, 1);
	__register_function(ctx, "sysinfo", _os_sysinfo, 1);
	__register_function(ctx, "error", _os_error, 0);
	__register_function(ctx, "set_signal_handler", _os_set_signal_handler, 1);
	__register_function(ctx, "signal", _os_signal, __VARARGS);
	__register_function(ctx, "alarm", _os_alarm, 1);
	__register_function(ctx, "eval_string", _os_eval_string, 1);
	__register_function(ctx, "eval_file", _os_eval_file, 1);

	__end_object(ctx)

	return 0;
}

